<?php
use App\Admin\Models\Config;
use App\Admin\Models\SystemModel;
use App\Admin\Utils\Admin;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\File;

// 当前管理员是否有数据恢复权限
function isRestore()
{
    return Admin::user()->can('pass-restore');
}

/**
 * 二维数组合并重复项
 * @param array $arr 传入数组
 * @param string $key 判断的键值
 * @return array $res
 */
function array_restruct($arr, $key)
{
    $res = array_column($arr, NULL, $key);
    foreach ($res as &$value) {
        $value = array();
    }
    foreach($arr as $v) {
        array_push($res[$v[$key]], $v);
    }
    return $res;
}






/**
 * 二维数组排序
 * @param array $arr 传入数组
 * @param string $key 需要排序的键值
 * @param int $order/$type
 * @return array 转换得到的数组
 */
function array_key_sort($arr, $key, $order=SORT_ASC, $type=SORT_NUMERIC)
{  
    if(is_array($arr)){  
        if (empty($arr)) {
            return [];
        }
        foreach ($arr as $array){  
            if (is_array($array)) {  
                $key_arr[] = $array[$key];  
            } else {  
                return false;  
            }  
        }  
    }else{  
        return false;  
    } 
    array_multisort($key_arr, $order, $type, $arr);  
    return $arr;  
}







/**
 * 横杠转下划线
 * @param string $str
 * @return string
 */
function barToUnderline($str) 
{
    return str_replace('-', '_', $str);
}





/**
 * 下划线转横杠
 * @param string $str
 * @return string
 */
function underlineToBar($str) 
{
    return str_replace('_', '-', $str);
}






/**
 * 发送get请求
 * @param string $url
 * @param array $header
 * @return int
 **/
function curl_get($url,$header=[]) 
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    //curl_setopt($ch, CURLOPT_HEADER, 1)#我不需要获取头部啊;

    //设置头
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT,  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
    curl_setopt($ch, CURLOPT_AUTOREFERER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 16);
    curl_setopt($ch, CURLOPT_TIMEOUT, 300);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
    $output = curl_exec($ch);
    curl_close($ch);
    return  $output;
}






/**
 * 发送post请求
 * @param string $url
 * @param mixed $post_data
 * @param array $header
 * @return $output
 **/
function curl_post($url = '', $post_data = false,$header=[]) 
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // post数据
    curl_setopt($ch, CURLOPT_POST, 1);
    // post的变量
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    //设置头
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT,  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//这个是重点,不进行ssl验证,HTTPS就乖乖打开吧 .
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}






/**
 * 字段属性转验证规则
 * @param string $tableName
 * @param object $indexes
 * @param object $column
 * @return string
 **/
function column_to_rules($tableName, $indexes, $column) 
{   
    $rules = [];
    foreach ($indexes as $index) {
        if (
            $index->getColumns()[0] == $column->getName() && 
            $index->isUnique()
        ) {
            array_push($rules, "unique:{$tableName},{$column->getName()}");
        }
    }
    if ($column->getNotnull()) {
        array_push($rules, 'required');
    } else {
        array_push($rules, 'nullable');
    }
    if ($column->getLength()) {
        array_push($rules, 'max:'.$column->getLength());
    }
    if ($column->getUnsigned()) {
        array_push($rules, 'min:0');
    }
    switch ($column->getType()->getName()) {
        case 'datetime':
        case 'timestamp':
            array_push($rules, 'date');
            break;
    }
    return implode('|', $rules);
}







/**
 * curl上传文件
 * @param string $url
 * @param array $params
 * @param array $header
 * @return $output
*/
function curl_upload($url,$params,$header) {
    $ch = curl_init();//初始化curl
    curl_setopt($ch, CURLOPT_URL, $url);//地址
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_TIMEOUT, 500);
    curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT,  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}






/**
 * demos表字段类型强制对照
 * @param String $slug
 * @return string
 **/
function demos_type_contrast($slug) 
{
    switch ($slug) {
        case 'id':
            $result = 'input';
            break;
        case 'created_at':
        case 'updated_at':
        case 'deleted_at':
            $result = 'datetime';
            break;
        default :
            $result = $slug;
            break;
    }
    return $result;
}


/**
 * 下载文件
 * @param string $filePath
 */
function downfile($filePath, $filename=null)
{
    ob_start(); 
    if (strstr($filename, '/')) {
        $filePathArr = explode('/', $filePath);
        $filename = end($filePathArr);
    }
    $size = readfile($filePath);
    header( "Content-type:  application/octet-stream "); 
    header( "Accept-Ranges:  bytes "); 
    header( "Content-Disposition:  attachment;  filename=".$filename); 
    header( "Accept-Length: " .$size);
}






/**
 * 递归删除目录
 * @param string $path
 * @return bool 
 */
function deldir($path){
    //如果是目录则继续
    if(is_dir($path)){
        //扫描一个文件夹内的所有文件夹和文件并返回数组
        $p = scandir($path);
        //如果 $p 中有两个以上的元素则说明当前 $path 不为空
        if(count($p)>2){
            foreach($p as $val){
                //排除目录中的.和..
                if($val !="." && $val !=".."){
                    //如果是目录则递归子目录，继续操作
                    if(is_dir($path.$val)){
                        //子目录中操作删除文件夹和文件
                        deldir($path.$val.'/');
                    }else{
                        //如果是文件直接删除
                        unlink($path.$val);
                    }
                }
            }
        }
    }
    //删除目录
    return rmdir($path);
}







/**
 * 生成假的路径, 文件路径, 地址路径
 *
 * @param int $min
 * @param int $max
 *
 * @return string
 */
function fake_path($min = 2, $max = 4)
{
    $faker = app(\Faker\Generator::class);
    return implode('/', $faker->words($faker->numberBetween($min, $max)));
}







/**
 * 获取http状态码
 * @param string $password
 * @param string $md5
 * @return bool
 */
function getHttpStatus()
{
    $objClass = new \ReflectionClass(\Symfony\Component\HttpFoundation\Response::class);
    // 此处获取类中定义的全部常量 返回的是 [key=>value,...] 的数组
    // key是常量名 value是常量值
    return array_values($objClass->getConstants());
}







/**
 * 获取随机字符串
 * @param int $len 长度
 * @param string $chars 字符
 */
function getRandomString($len, $chars=null)  
{  
    if (is_null($chars)) {  
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";  
    }  
    mt_srand(10000000*(double)microtime());  
    for ($i = 0, $str = '', $lc = strlen($chars)-1; $i < $len; $i++) {  
        $str .= $chars[mt_rand(0, $lc)];  
    }  
    return $str;  
}





/**
 * 获取远程文件并下载
 * @param string $url
 * @param string $save_dir
 * @param string $filename
 * @param int $type
 * @return array
 */
function getFile($url, $save_dir = '', $filename = '', $type = 0) {  
    if (trim($url) == '') {  
        return false;  
    }  
    if (trim($save_dir) == '') {  
        $save_dir = './';  
    }  
    if (0 !== strrpos($save_dir, '/')) {  
        $save_dir.= '/';  
    }  
    //创建保存目录  
    if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {  
        return false;  
    }  
    //获取远程文件所采用的方法  
    if ($type) {  
        $ch = curl_init();  
        $timeout = 5;  
        curl_setopt($ch, CURLOPT_URL, $url);  
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);  
        $content = curl_exec($ch);  
        curl_close($ch);  
    } else {  
        ob_start();  
        readfile($url);  
        $content = ob_get_contents();  
        ob_end_clean();  
    }  
    //echo $content;  
    $size = strlen($content);  
    //文件大小  
    $fp2 = @fopen($save_dir . $filename, 'a');  
    fwrite($fp2, $content);  
    fclose($fp2);  
    unset($content, $url);  
    return array(  
        'file_name' => $filename,  
        'save_path' => $save_dir . $filename,  
        'file_size' => $size  
    );  
}







/**
 * 一个数组根据另一个数组排序
 * @param array $arr1
 * @param array $arr2
 * @param bool $keep
 * @return array 
 */
function orderByArray($arr1, $arr2, $keep=false){
    $orderData = array_intersect_key(array_flip($arr2),$arr1);
    foreach ($orderData as $key => $value) {
        $orderData[$key] = $arr1[$key];
    }

    return $keep ? $orderData : array_values($orderData);
}






/**
 * 对象转数组
 * @param object $object
 * @return array
 */
function objToArr($object) {
    return json_decode(json_encode($object), true);
}










/**
 * 解析选项设置
 * @param array $data
 * @param string $scene
 * @return array $data
 */
function parseOptions($data, $scene){
    switch ($scene) {
        case 'search':
            if ($data['type'] == SystemModel::TYPE_CASCADER) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        break;
                    case '2':
                        $results = DB::select($data['options']['options']);
                        $tree = [];
                        foreach ($results as $row) {
                            if (!$row->parent_id) {
                                $tree[] = [
                                    'value' => $row->value,
                                    'label' => $row->label,
                                    'children' => [],
                                ];
                            } else {

                                $parentIndex = findChildrenIndex($tree, $row->parent_id);
                                if ($parentIndex) {
                                    $tree[$parentIndex]['children'][] = [
                                        'value' => $row->value,
                                        'label' => $row->label,
                                    ];
                                }
                            }
                        }
                        $data['options']['options'] = $tree;
                        break;
                    case '3':
                        $options = Config::whereId($data['options']['options'])->value('options');
                        $temp = $data;
                        $temp['options']['options'] = $options['options'];
                        $temp['options']['sample'] = 1;
                        $data['options'] = parseOptions($temp, 'search');
                        break;
                    case '4':
                        $file = public_path($data['options']['options']['path']);
                        $pairs = json_decode(File::get($file), true);
                        $data['options']['options'] = $pairs;
                        break;
                }
            } elseif ($data['type'] == SystemModel::TYPE_SELECT_TREE) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        addNodeString($data['options']['options']);
                        $data['options']['options'] = nestedToSelectOptions(
                            $data['options']['options'], 
                            array(
                                'id' => 'value',
                                'title' => 'label',
                                'node_string' => 'node_string',
                                'children' => 'children'
                            ),
                            false
                        );
                        break;
                    case '2':
                        DB::enableQueryLog();
                        $options = objToArr(DB::select($data['options']['options']));
                        $explainArr = objToArr(explainSql(DB::getQueryLog()));
                        $tables = array_column(current($explainArr)['explain'], 'table');
                        $posTables = [];
                        $minPos = INF;
                        foreach ($tables as $table) {
                            $pos = min($minPos, strpos($data['options']['options'], $table));
                            $pos>0 && $posTables[$pos] = $table;
                        }
                        sort($posTables);
                        $data['model'] = str_replace('_', '-', current($posTables));
                        $dummyResource = Str::camel(Str::singular($data['model']));
                        $ucDummyResource = Str::ucfirst($dummyResource);
                        $ucDummyResource = "App\Admin\Models\\$ucDummyResource";
                        $model = new $ucDummyResource;
                        if (method_exists($model, 'treeInclude')) {
                            $data['options']['options'] = (new $ucDummyResource)->treeExcept(0)->toNodeTree();
                            $data['options']['options'] = nestedToSelectOptions($data['options']['options'], [], false);
                        }   
                        break;
                }
            } else {
                if (isset($data['options']['sample']) && $data['options']['sample']==2) {
                    $options = objToArr(DB::select($data['options']['options']));
                    $data['options']['options'] = [];
                    foreach ($options as $key => $value) {
                        $id = current($value);
                        $name = end($value);
                        if ($id && $name) {
                            array_push($data['options']['options'],[
                                'id'=>$id,
                                'name'=>$name,
                            ]);
                        }
                    }
                } elseif (isset($data['options']['sample']) && $data['options']['sample']==3) {
                    $options = Config::whereId($data['options']['options'])->value('options');
                    $temp = $data;
                    $temp['options']['options'] = $options['options'];
                    $temp['options']['sample'] = 1;
                    $data['options'] = parseOptions($temp, 'search');
                } else {
                    $data['options']['options'] = explode("\n", $data['options']['options']);
                    foreach ($data['options']['options'] as $key => $value) {
                        $temp = explode('=>', $value);
                        unset($data['options']['options'][$key]);
                        $data['options']['options'][$key]['id'] = $temp[0];
                        $data['options']['options'][$key]['name'] = $temp[1];
                    }
                }
            }
            break;
        case 'form':
            if ($data['type'] == SystemModel::TYPE_CASCADER) {
                switch ($data['options']['sample']) {
                    case '2':
                        $results = DB::select($data['options']['options']);
                        $tree = [];
                        foreach ($results as $row) {
                            if (!$row->parent_id) {
                                $tree[] = [
                                    'value' => $row->value,
                                    'label' => $row->label,
                                    'children' => [],
                                ];
                            } else {

                                $parentIndex = findChildrenIndex($tree, $row->parent_id);
                                if ($parentIndex) {
                                    $tree[$parentIndex]['children'][] = [
                                        'value' => $row->value,
                                        'label' => $row->label,
                                    ];
                                }
                            }
                        }
                        $data['options']['options'] = $tree;
                        break;
                    case '4':
                        $file = public_path($data['options']['options']['path']);
                        $pairs = json_decode(File::get($file), true);
                        $data['options']['options'] = $pairs;
                        break;
                }
            } elseif ($data['type'] == SystemModel::TYPE_SELECT_TREE) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'],true);
                        addNodeString($data['options']['options']);
                        break;
                    case '2':
                        DB::enableQueryLog();
                        $options = objToArr(DB::select($data['options']['options']));
                        $explainArr = objToArr(explainSql(DB::getQueryLog()));
                        $tables = array_column(current($explainArr)['explain'], 'table');
                        $posTables = [];
                        $minPos = INF;
                        foreach ($tables as $table) {
                            $pos = min($minPos, strpos($data['options']['options'], $table));
                            $pos>0 && $posTables[$pos] = $table;
                        }
                        sort($posTables);
                        $data['options']['model'] = str_replace('_', '-', current($posTables));
                        $data['options']['options'] = [];
                        foreach ($options as $value) {
                            array_push($data['options']['options'], current($value).'=>'.end($value));
                        }
                        $data['options']['options'] = implode("\n", $data['options']['options']); 
                        $dummyResource = Str::camel(Str::singular($data['options']['model']));
                        $ucDummyResource = Str::ucfirst($dummyResource);
                        $ucDummyResource = "App\Admin\Models\\$ucDummyResource";
                        $model = new $ucDummyResource;
                        $includeIds = array_column($options, 'id');
                        if (method_exists($model, 'treeInclude')) {
                            $data['options']['options'] = (new $ucDummyResource)->treeInclude($includeIds)->toNodeTree();
                        }    
                        break;
                    case '4':
                        $file = public_path($data['options']['options']['path']);
                        $pairs = json_decode(File::get($file), true);
                        $data['options']['options'] = $pairs;
                        addNodeString($data['options']['options']);
                        break;
                }
            } elseif (
                $data['type'] == SystemModel::TYPE_SINGLE || 
                $data['type'] == SystemModel::TYPE_MULTIPLE
            ) {
                switch ($data['options']['sample']) {
                    case '2':
                        DB::enableQueryLog();
                        $options = objToArr(DB::select($data['options']['options']));
                        $explainArr = objToArr(explainSql(DB::getQueryLog()));
                        $tables = array_column(current($explainArr)['explain'], 'table');
                        $posTables = [];
                        $minPos = INF;
                        foreach ($tables as $table) {
                            $pos = min($minPos, strpos($data['options']['options'], $table));
                            $pos>0 && $posTables[$pos] = $table;
                        }
                        sort($posTables);
                        $data['options']['model'] = str_replace('_', '-', current($posTables));
                        $data['options']['options'] = [];
                        foreach ($options as $value) {
                            array_push($data['options']['options'], current($value).'=>'.end($value));
                        }
                        $data['options']['options'] = implode("\n", $data['options']['options']);
                        break;
                    case '3':
                        $options = Config::whereId($data['options']['options'])->value('options');
                        $data['options']['options'] = $options['options'];
                        break;
                }
            } else {
                if (isset($data['options']['sample']) && $data['options']['sample']==2) {
                    DB::enableQueryLog();
                    $options = objToArr(DB::select($data['options']['options']));
                    $explainArr = objToArr(explainSql(DB::getQueryLog()));
                    $tables = array_column(current($explainArr)['explain'], 'table');
                    $posTables = [];
                    $minPos = INF;
                    foreach ($tables as $table) {
                        $pos = min($minPos, strpos($data['options']['options'], $table));
                        $pos>0 && $posTables[$pos] = $table;
                    }
                    sort($posTables);
                    $data['options']['model'] = str_replace('_', '-', current($posTables));
                    $data['options']['options'] = [];
                    foreach ($options as $value) {
                        array_push($data['options']['options'], current($value).'=>'.end($value));
                    }
                    $data['options']['options'] = implode("\n", $data['options']['options']);            
                } elseif (isset($data['options']['sample']) && $data['options']['sample']==3) {
                    $options = Config::whereId($data['options']['options'])->value('options');
                        $data['options']['options'] = $options['options'];
                }
                break;
            }
            break;
        case 'list':
            if ($data['type'] == SystemModel::TYPE_CASCADER) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        break;
                    case '2':
                        $results = DB::select($data['options']['options']);
                        $tree = [];
                        foreach ($results as $row) {
                            if (!$row->parent_id) {
                                $tree[] = [
                                    'value' => $row->value,
                                    'label' => $row->label,
                                    'children' => [],
                                ];
                            } else {

                                $parentIndex = findChildrenIndex($tree, $row->parent_id);
                                if ($parentIndex) {
                                    $tree[$parentIndex]['children'][] = [
                                        'value' => $row->value,
                                        'label' => $row->label,
                                    ];
                                }
                            }
                        }
                        $data['options']['options'] = $tree;
                        break;
                    case '4':
                        $file = public_path($data['options']['options']['path']);
                        $pairs = json_decode(File::get($file), true);
                        $data['options']['options'] = $pairs;
                        break;
                }
            } elseif ($data['type'] == SystemModel::TYPE_SELECT_TREE) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        break;
                }
            } else {
                if (isset($data['options']['sample']) && $data['options']['sample']==1) {
                    $data['options']['options'] = explode("\n", $data['options']['options']);
                    foreach ($data['options']['options'] as $key => $value) {
                        $temp = explode('=>', $value);
                        unset($data['options']['options'][$key]);
                        $data['options']['options'][$key]['id'] = $temp[0];
                        $data['options']['options'][$key]['name'] = $temp[1];
                    }
                    $data['options']['options'] = array_column($data['options']['options'], 'name', 'id');
                } elseif (isset($data['options']['sample']) && $data['options']['sample']==2) {
                    $options = objToArr(DB::select($data['options']['options']));
                    $data['options']['options'] = [];
                    foreach ($options as $key => $value) {
                        $data['options']['options'][$key]['id'] = current($value);
                        $data['options']['options'][$key]['name'] = end($value);
                    }
                    $data['options']['options'] = array_column($data['options']['options'], 'name', 'id');         
                } elseif (isset($data['options']['sample']) && $data['options']['sample']==3) {
                    $options = Config::whereId($data['options']['options'])->value('options');
                    $temp = $data;
                    $temp['options']['options'] = $options['options'];
                    $temp['options']['sample'] = 1;
                    $data['options'] = parseOptions($temp, 'list');
                } 
            }
            break;
        case 'detail':
            if ($data['type'] == SystemModel::TYPE_CASCADER) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        break;
                    case '2':
                        $results = DB::select($data['options']['options']);
                        $tree = [];
                        foreach ($results as $row) {
                            if (!$row->parent_id) {
                                $tree[] = [
                                    'value' => $row->value,
                                    'label' => $row->label,
                                    'children' => [],
                                ];
                            } else {

                                $parentIndex = findChildrenIndex($tree, $row->parent_id);
                                if ($parentIndex) {
                                    $tree[$parentIndex]['children'][] = [
                                        'value' => $row->value,
                                        'label' => $row->label,
                                    ];
                                }
                            }
                        }
                        $data['options']['options'] = $tree;
                        break;
                    case '4':
                        $file = public_path($data['options']['options']['path']);
                        $pairs = json_decode(File::get($file), true);
                        $data['options']['options'] = $pairs;
                        break;
                }
            } elseif ($data['type'] == SystemModel::TYPE_SELECT_TREE) {
                switch ($data['options']['sample']) {
                    case '1':
                        $data['options']['options'] = json_decode($data['options']['options'], true);
                        break;
                }
            } elseif ($data['type'] == SystemModel::TYPE_FILE) {
                break;
            } else {
                if (isset($data['options']['sample']) && $data['options']['sample']==2) {
                    $options = objToArr(DB::select($data['options']['options']));
                    $data['options']['options'] = [];
                    foreach ($options as $key => $value) {
                        $data['options']['options'][$key]['id'] = current($value);
                        $data['options']['options'][$key]['name'] = end($value);
                    }
                    $data['options']['options'] = array_column($data['options']['options'], 'name', 'id');
                } elseif (isset($data['options']['sample']) && $data['options']['sample']==3) {
                    $options = Config::whereId($data['options']['options'])->value('options');
                    $data['options']['options'] = $options['options'];
                } else {
                    $data['options']['options'] = explode("\n", $data['options']['options']);
                    foreach ($data['options']['options'] as $key => $value) {
                        $temp = explode('=>', $value);
                        unset($data['options']['options'][$key]);
                        $data['options']['options'][$key]['id'] = $temp[0];
                        $data['options']['options'][$key]['name'] = $temp[1];
                    }
                    $data['options']['options'] = array_column($data['options']['options'], 'name', 'id');
                }
            }
            break;
    }
    return $data['options'];
}

function findChildrenIndex($tree, $parentId) {
    foreach ($tree as $index => $children) {
        if ($children['value'] === $parentId) {
            return $index;
        }
        if (isset($children['children'])) {
            $childIndex = findChildrenIndex($children['children'], $parentId);
            if ($childIndex) {
                return $childIndex;
            }
        }
    }
    return null;
}






/**
 * 字符串转数组
 * @param string $str
 * @return string
 */
function stringToArr($str, $separator=',') {
    if (is_string($str)) {
        return explode($separator, $str);
    }
    return [$str];
}






/**
 * 字段类型对照
 * @param Type $type
 * @return string
 **/
function type_contrast($type) {
    $name = $type->getName();
    $result = 'input';
    if ($type->hasType($name)) {
        switch ($name) {
            case 'date':
                $result = 'date';
                break;
            case 'time':
                $result = 'time';
                break;
            case 'datetime':
            case 'timestamp':
                $result = 'datetime';
                break;
            case 'tinyint':
            case 'smallint':
            case 'mediumint':
            case 'int':
            case 'integer':
            case 'bigint':
            case 'float':
            case 'double':
            case 'decimal':
            case 'char':
                $result = 'input';
                break;
            case 'varchar':
            case 'tinyblob':
            case 'tinytext':
                $result = 'textarea';
                break;
            case 'blob':
            case 'text':
            case 'mediumblob':
            case 'mediumtext':
            case 'longblob':
            case 'longtext':
                $result = 'editor';
                break;
        }
    }
    return $result;
}






/**
 * 转Sql语句
 * @param object $builder
 * @return $sql
 **/
function toSql($builder) {
    $bindings = $builder->getBindings();
    $sql = str_replace('?', '%s', $builder->toSql());
    $sql = sprintf($sql,...$bindings);
    return $sql;
}






/**
 * 生成UUID
 * @return string
 **/
function uuid() {  
    $chars = md5(uniqid(mt_rand(), true));  
    $uuid = substr ( $chars, 0, 8 ) . '-'
        . substr ( $chars, 8, 4 ) . '-' 
        . substr ( $chars, 12, 4 ) . '-'
        . substr ( $chars, 16, 4 ) . '-'
        . substr ( $chars, 20, 12 );  
    return $uuid ;  
}  






/**
 * 分析sql语句
 * @param array $getQueryLog
 * @return $sqlArr
 **/
function explainSql($getQueryLog)
{
    $sqlArr = [];
    foreach ($getQueryLog as $k=>$log){
        $sql = $log['query'];
        foreach ($log['bindings'] as $binding){
            $binding = is_numeric($binding) ? $binding : "'".$binding."'";
            //正则匹配替换
            $sql = preg_replace('/\?/',$binding,$sql,1);
        }
        //输出sql语句
        $sqlArr[$k]['sql'] = $sql;
        //执行时间
        $sqlArr[$k]['time'] = $log['time'];
        //使用explain分析sql语句
        $sqlArr[$k]['explain'] = \DB::select('explain '.$log['query'],$log['bindings']);
    }
    DB::flushQueryLog();
    DB::disableQueryLog();
    return $sqlArr;
}

/**
 * 把嵌套数据构建成 select 的缩进形式的 options
 *
 * @param $items
 * @param $props
 * @return array
 */
function nestedToSelectOptions($items, $props = array(), $firstLevel = array('id' => 0, 'title' => '一级', 'text' => '一级')) {

  if (!is_array($items)) {
    return array();
  }
  $defaultProps = array(
    'id' => 'id',
    'title' => 'title',
    'node_string' => 'node_string',
    'children' => 'children',
    'firstLevel' => $firstLevel,
  );

  $props = array_merge($defaultProps, $props);
  $_build = function ($items, $indent) use ($props, &$_build) {
    $options = array();
    foreach ($items as $i) {
      $options[] = array(
        'id' => $i[$props['id']],
        'text' => str_repeat('　', $indent) . $i[$props['title']],
        'title' => $i[$props['node_string']],
      );
      if (isset($i[$props['children']])) {
        $options = array_merge($options, $_build($i[$props['children']], $indent + 2));
      }
    }
    return $options;
  };

  // 如果不需要追加顶级选项，则初始缩进为 0
  $res = $_build($items, $props['firstLevel'] ? 2 : 0);
  $props['firstLevel'] && array_unshift($res, $props['firstLevel']);
  return $res;
}

function addNodeString(&$data, $parentLabel = '') {
    foreach ($data as &$item) {
        $label = $parentLabel . ($parentLabel ? '-' : '') . $item['label'];
        $item['node_string'] = $label;
        if (isset($item['children']) && is_array($item['children'])) {
            addNodeString($item['children'], $label);
        }
    }
}